home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / bit / src / iutil.c < prev    next >
C/C++ Source or Header  |  1994-08-01  |  54KB  |  2,363 lines

  1. /*
  2.  * $Id: iutil.c,v 0.91 1994/02/20 00:53:07 zhao Pre-Release $
  3.  *
  4.  *. This file is part of BIT shareware package. After the two weeks of
  5.  *  free evaluation period, you are encouraged (required) to register
  6.  *  your copy for a small registration fee, which is $35 for personal use
  7.  *  and $50 for commercial, government and institutional use.
  8.  *
  9.  *  Copyright(c) 1993, 1994 by T.C. Zhao.
  10.  *  All rights reserved.
  11.  *
  12.  *  Permission to use, copy, and distribute this software in its entirety
  13.  *  for non-commercial purposes is hereby granted, provided that the
  14.  *  above shareware and copyright notices and this permission notice
  15.  *  appear in all copies and their documentation.
  16.  *
  17.  *  This software may be modified for your own use, but modified versions
  18.  *  may not be distributed without prior consent of the author.
  19.  *
  20.  *  This software is provided "as is" without expressed or implied
  21.  *  warranty of any kind.
  22.  *
  23.  *.
  24.  *
  25.  * utilities dealing with memory allocations and image manipulations
  26.  */
  27. #if !defined(lint) && defined(F_ID)
  28. char *id_iutil = "$Id: iutil.c,v 0.91 1994/02/20 00:53:07 zhao Pre-Release $";
  29. #endif
  30.  
  31. #include "bit.h"
  32. #include "extern.h"
  33. #include "dmalloc.h"
  34.  
  35. /****************** Defines and limits *****************************/
  36.  
  37. #define CONVERT_TYPE        /* controls the rgb->gray lookup table */
  38.  
  39. #include "lookup.h"
  40.  
  41. /*****************************************************************
  42.  * Gather all recognized format info which is output by function out
  43.  * defined  as void (*out)(char *)
  44.  ******************************************************************/
  45. void
  46. enumerate_formats(void (*out) (const char *))
  47. {
  48.     char lstr[100];
  49.     const char *fmt;
  50.     IMG_IO *ios = img_io + totalfmt, *io = img_io;
  51.  
  52.     if (!out)
  53.       {
  54.       M_warn("EnumerateFormats", "Bad output function");
  55.       return;
  56.       }
  57.  
  58.     /* write only +, read only - */
  59.     while (io < ios)
  60.       {
  61.       fmt = (!io->load) ? "%s(%s)+" :
  62.           (io->dump ? "%s(%s)" : "%s(%s)-");
  63.       sprintf(lstr, fmt, io->info, io->key);
  64.       out(lstr);
  65.       io++;
  66.       }
  67. }
  68.  
  69. /***************************************************************
  70.  * Gather all formats that are capable of writing
  71.  **************************************************************/
  72. void
  73. init_w_formats(void)
  74. {
  75.     if (!totalwrite)
  76.       {
  77.       register IMG_IO *ios = img_io + totalfmt, *io = img_io;
  78.  
  79.       while (io < ios)
  80.         {
  81.         if (io->dump)
  82.             wio[totalwrite++] = io;
  83.         io++;
  84.         }
  85.       }
  86. }
  87.  
  88.  
  89. /****************************************************************
  90.  * Insert a pixel into a matrix. Pixel is represented by
  91.  * a 4-element vector, the first 3 is RGB component and the
  92.  * 4th is the colorindex if the image is in CI
  93.  ****************************************************************/
  94. void
  95. pack_pixel(IPTR im, void *m, int py, int px, int pc[])
  96. {
  97.     if (IS_CI(im))
  98.       {
  99.       ((ci_t **) m)[py][px] = pc[3];
  100.       }
  101.     else
  102.       {
  103.       ((rgba_t **) m)[py][px] = Pack(pc[0], pc[1], pc[2]);
  104.       }
  105. }
  106.  
  107. /*************************************************************
  108.  * pick a pixel from a matrix
  109.  **************************************************************/
  110. void
  111. pick_pixel(IPTR im, void *m, int py, int px, int pc[])
  112. {
  113.     int ci;
  114.  
  115.     if (IS_CI(im))
  116.       {
  117.       pc[3] = ci = ((ci_t **) m)[py][px];
  118.       pc[0] = im->cmap->ct[0][ci];
  119.       pc[1] = im->cmap->ct[1][ci];
  120.       pc[2] = im->cmap->ct[2][ci];
  121.       }
  122.     else
  123.       {
  124.       rgba_t p = ((rgba_t **) m)[py][px];
  125.       Unpack(p, pc[0], pc[1], pc[2]);
  126.       pc[3] = 0;
  127.       }
  128. }
  129.  
  130. /****************************************************
  131.  * Routines that deal with separate RGB matrices
  132.  ***************************************************/
  133. void
  134. img_free_rgbmem(IPTR im)
  135. {
  136.     free_mat(im->pc[0]);
  137.     if (im->pc[0] != im->pc[1])
  138.       {                /* if equal, must be gray */
  139.       free_mat(im->pc[1]);
  140.       free_mat(im->pc[2]);
  141.       }
  142.     im->pc[0] = im->pc[1] = im->pc[2] = 0;
  143. }
  144.  
  145. void
  146. img_replace_rgb(IPTR im, pc_t **r, pc_t **g, pc_t **b)
  147. {
  148.     if (im->pc[0] != r)
  149.     img_free_rgbmem(im);
  150.     im->pc[0] = r;
  151.     im->pc[1] = g;
  152.     im->pc[2] = b;
  153. }
  154.  
  155. /****************************************************************
  156.  * get_rgbmem must get RM, GM, BM regardless of the image type.
  157.  * otherwise, need to change many routines regarding R,G,B matrices
  158.  ***************************************************************/
  159.  
  160. int
  161. img_get_rgbmem(IPTR im)
  162. {
  163.     pc_t **r, **g = 0, **b = 0;
  164.  
  165.     if (!(r = get_mat(im->h, im->w, sizeof(pc_t))) ||
  166.     ! (g = get_mat(im->h, im->w, sizeof(pc_t))) ||
  167.     ! (b = get_mat(im->h, im->w, sizeof(pc_t))))
  168.       {
  169.       free_mat(r);
  170.       free_mat(g);
  171.       free_mat(b);
  172.       return -1;
  173.       }
  174.     img_replace_rgb(im, r, g, b);
  175.     return 0;
  176. }
  177.  
  178. /*********************************************************
  179.  * routines that deal with raster mem
  180.  *********************************************************/
  181. void
  182. img_free_rastermem(IPTR im)
  183. {
  184.     if (im->size > 2 && im->mraster)
  185.       {
  186.       if (((char **) im->mraster)[0] != (char *) im->raster)
  187.         {
  188.         Bark("FreeRasterMem", "memory corrupt");
  189.         return;
  190.         }
  191.       free_mat(im->mraster);
  192.       im->size = im->ok = 0;
  193.       im->mraster = 0;
  194.       }
  195.     return;
  196. }
  197.  
  198. extern void exit(int);
  199.  
  200. IPTR
  201. get_mem_imgptr(void)
  202. {
  203.     const char *fn = "GetMemIptr";
  204.     IPTR p = calloc(1, sizeof(*p));
  205.  
  206.     if (!p)
  207.       {
  208.       M_err(fn, mfailed);
  209.       if (win_id > 0)
  210.           Bark(fn, mfailed);
  211.       clean_up();
  212.       }
  213.  
  214.     /* initialize all pointers and non-zero default */
  215.     p->type = T_FLEX;
  216.     p->mraster = p->raster = 0;
  217.     p->cmap = 0;
  218.     p->pc[0] = p->pc[1] = p->pc[2] = 0;
  219.     p->fp = 0;
  220.     p->aspect = 1000;
  221.     p->comm = 0;
  222.  
  223.     return p;
  224. }
  225.  
  226. /*******************************************************
  227.  * Colormaps
  228.  *******************************************************/
  229.  
  230. /* Demand a colormap. If unsuccesful, quit */
  231. CMPTR
  232. get_mem_cmap(void)
  233. {
  234.     CMPTR p = calloc(1, sizeof(*p));
  235.  
  236.     if (!p)
  237.       {
  238.       M_err("GetMemCmap", mfailed);
  239.       if (win_id > 0)
  240.           Bark("GetMemCmap", mfailed);
  241.       clean_up();
  242.       }
  243.     p->colors = p->ucolors = p->packed = 0;
  244.  
  245.     return p;
  246. }
  247.  
  248. void
  249. free_mem_imgptr(IPTR p)
  250. {
  251.     if (p)
  252.       {
  253.       p->ok = p->size = 0;
  254.       p->mraster = 0;
  255.       free(p);
  256.       }
  257. }
  258.  
  259. void
  260. free_mem_cmap(CMPTR p)
  261. {
  262.     free(p);
  263. }
  264.  
  265. int
  266. img_get_rastermem(IPTR im)
  267. {
  268.     register void *p, **pp;
  269.     register size_t esize = 0;
  270.     const char *fn = "GetRasterMem";
  271.  
  272.     /* this theoretically should never happen */
  273.     if (!im)
  274.       {
  275.       Bark(fn, "Something is very wrong");
  276.       return -1;
  277.       }
  278.  
  279.     if (im->type == T_FLEX || im->w < 1 || im->h < 1)
  280.       {
  281.       Bark(fn, "%s: Bad %s description", im->ifile,
  282.            im->io ? im->io->key : "???");
  283.       return -1;
  284.       }
  285.  
  286.     if (IS_CI(im))
  287.     im->esize = esize = sizeof(ci_t);
  288.     else if (IS_CPACK(im))
  289.     im->esize = esize = sizeof(rgba_t);
  290.     else
  291.       {
  292.       Bark(fn, "Bad Image type");
  293.       clean_up();
  294.       }
  295.  
  296.     img_free_rastermem(im);
  297.  
  298.     if (!(p = get_mat(im->h, im->w, esize)))
  299.       {
  300.       im->size = 0;
  301.       return -1;
  302.       }
  303.  
  304.     pp = p;
  305.     im->mraster = pp;
  306.     im->raster = pp[0];
  307.     im->size = esize * im->w * im->h;
  308.  
  309.     return 0;
  310. }
  311.  
  312. /*
  313.  * this function is really overkill, im->ok should be able to indicate if the
  314.  * image is ready. Be on the safe side, also might catch unexpected errors
  315.  */
  316. int
  317. image_ready(IPTR im, const char *func)
  318. {
  319.     int p = (im != 0 && im->ok
  320.          && im->size > 1
  321.          && im->w >= 1
  322.          && im->mraster
  323.          && im->raster
  324.          && (IS_CPACK(im) || IS_CI(im)));
  325.  
  326.     if (!p)
  327.     Bark(func, "No image or bad type");
  328.     return p;
  329. }
  330.  
  331. /*
  332.  * duplicate an image raster;
  333.  */
  334. int
  335. img_dup_raster(IPTR new, IPTR old)
  336. {
  337.     const char *fn = "RasterDup";
  338.  
  339.     if (!image_ready(old, fn) || !new)
  340.     return -1;
  341.  
  342.     new->w = old->w;
  343.     new->h = old->h;
  344.     new->type = old->type;
  345.  
  346.     return (img_get_rastermem(new) < 0 ||
  347.         memcpy(new->raster, old->raster, new->size) == 0) ? -1 : 0;
  348. }
  349.  
  350. void
  351. img_free_cmap(IPTR im)
  352. {
  353.     if (im && im->cmap)
  354.       {
  355.       free_mem_cmap(im->cmap);
  356.       im->cmap = 0;
  357.       }
  358. }
  359.  
  360. /*****************************************************************
  361.  * duplicate a colormap (free the old one if present)
  362.  *****************************************************************/
  363.  
  364. int
  365. img_dup_cmap(IPTR new, IPTR old)
  366. {
  367.     if (!image_ready(old, "dup_raster") || !new)
  368.     return -1;
  369.     img_free_cmap(new);
  370.     new->cmap = get_mem_cmap();
  371.     return memcpy(new->cmap, old->cmap, sizeof(*old->cmap)) ? 0 : -1;
  372. }
  373.  
  374. /*******************************************************************
  375.  * duplicate an image and return the new image pointer
  376.  ********************************************************************/
  377.  
  378. IPTR
  379. img_dup(IPTR old)
  380. {
  381.     IPTR new;
  382.     int ok = -1;
  383.  
  384.     show_busy("ImageDup ...");
  385.  
  386.     new = get_mem_imgptr();
  387.     if (memcpy(new, old, sizeof(*old)) != 0)
  388.       {
  389.       new->size = new->ok = 0;
  390.       new->mraster = new->raster = 0;
  391.       new->cmap = 0;
  392.       ok = !(img_dup_cmap(new, old) || img_dup_raster(new, old));
  393.       new->ok = ok;
  394.       }
  395.     end_busy();
  396.  
  397.     return ok ? new : 0;
  398. }
  399.  
  400. void
  401. free_image_mem(IPTR im)
  402. {
  403.     if (!im)
  404.     return;
  405.     img_free_cmap(im);
  406.     img_free_rastermem(im);
  407.     img_free_rgbmem(im);
  408. }
  409.  
  410. /********************************************************************
  411.  * free everything that is associated with the image structure img
  412.  *
  413.  * free_rastermem
  414.  * free_cmap
  415.  * free_imgptr
  416.  *********************************************************************/
  417.  
  418. void
  419. free_image(IPTR im)
  420. {
  421.     if (im)
  422.       {
  423.       free_image_mem(im);
  424.       free_mem_imgptr(im);
  425.       }
  426. }
  427.  
  428. /***********************************************************************
  429.  * get the border offset into the image. Note MAXC is the maximum no. of
  430.  * colors on one line(horizontal or vertical) can have to be considered
  431.  * to be a border line. Coordinates are from Left to Right and Bottom to Top.
  432.  *********************************************************************/
  433.  
  434. #define MAXC   4
  435.  
  436. #define DOIT(type,nouse)                                           \
  437.         register type **mras= im->mraster, *ras, first;            \
  438.         do {                                                       \
  439.           ok= 1; ras= mras[h - 1];                                 \
  440.           for (j= h - 1; j >= 0 && ok; j--,(*t)++,ras= mras[j]){   \
  441.              first= *ras++;                                        \
  442.              for (i= 1 ; i < w && first== *ras;i++, ras++)         \
  443.                  ;                                                 \
  444.              ok= i== w;                                            \
  445.           }                                                        \
  446.           h -= *t; ok= 1; ras= mras[0];                            \
  447.           for (j= 0; j < h && ok; j++, (*b)++, ras= mras[j]) {     \
  448.             for (i= 0, first= *ras; ++i < w && first== *ras++;)    \
  449.                 ;                                                  \
  450.             ok= i== w;                                             \
  451.           }                                                        \
  452.           ok= 1;                                                   \
  453.           for (*l= 0; *l < w && ok; (*l)++) {                      \
  454.             first= mras[*b][*l];                                   \
  455.             for (j= *b; j < h  && ok; j++)                         \
  456.                 ok= first== mras[j][*l];                           \
  457.           }                                                        \
  458.           ok= 1;                                                   \
  459.           for (i= w - 1; i > *l && ok; i--, (*r)++) {              \
  460.             first= mras[*b][i];                                    \
  461.             for (j= *b; j < h  && ok; j++)                         \
  462.                 ok= first== mras[j][i];                            \
  463.           }                                                        \
  464.      } while (ZERO)
  465.  
  466. int
  467. img_get_border(IPTR im, int *b, int *l, int *t, int *r, int n)
  468. {
  469.     register int i, j, ok, h, w;
  470.  
  471.     if (!image_ready(im, "Border"))
  472.     return -1;
  473.  
  474.     *t = *l = *r = *b = 0;
  475.     h = im->h;
  476.     w = im->w;
  477.  
  478.     show_busy("PleaseWait ...");
  479.  
  480.     if (IS_CPACK(im))
  481.       {                /* in RGBA format */
  482.       DOIT(rgba_t, n);
  483.       }
  484.     else
  485.       {
  486.       DOIT(ci_t, n);
  487.       }
  488.     end_busy();
  489.  
  490.     return 0;
  491. }
  492.  
  493. /****************************************************************
  494.  * Note not true histograms, rather histogram for RGB separately.
  495.  * Histogram is not normalized.
  496.  ****************************************************************/
  497. int
  498. img_get_histogram(IPTR im)
  499. {
  500.     Hist_t *hist = im->cmap->p_h.hist;
  501.     long total = im->w * im->h;
  502.     int i, j;
  503.     double ave[4];
  504.  
  505. #ifdef MTRACE
  506.     M_trace("Histogram", "Entering");
  507. #endif
  508.  
  509.     show_busy("GettingHist ...");
  510.     (void) memset(hist, 0, sizeof(Hist_t) * 4);
  511.  
  512.     im->cmap->packed = 0;    /* overwrite packed arrays */
  513.  
  514.     if (IS_CPACK(im))
  515.       {
  516.       register rgba_t *rgba = im->raster, *rs;
  517.       register pc_t r;
  518.       if (IS_GRAY(im))
  519.         {
  520.         for (rs = rgba + total; rgba < rs; rgba++)
  521.           {
  522.               r = (*rgba & PCMAXV);
  523.  
  524.               /* check overflows */
  525.               if (++(hist[3][r]) == 0)
  526.               (hist[3][r])--;
  527.           }
  528.         }
  529.       else
  530.         {
  531.         register pc_t g, b;
  532.         for (rs = rgba + total; rgba < rs; rgba++)
  533.           {
  534.               Unpack(*rgba, r, g, b);
  535.               if (++(hist[0][r]) == 0)
  536.               (hist[0][r])--;
  537.               if (++(hist[1][g]) == 0)
  538.               (hist[1][g])--;
  539.               if (++(hist[2][b]) == 0)
  540.               (hist[2][b])--;
  541.               ++(hist[3][RGB2GRAY(r, g, b)]);
  542.           }
  543.         }
  544.       }
  545.     else
  546.       {                /* in cmap */
  547.       register ci_t *ci = im->raster, *cis;
  548.       register CMPTR m = im->cmap;
  549.       register pc_t *r = m->ct[0], *g = m->ct[1], *b = m->ct[2];
  550.       if (IS_GRAY(im))
  551.         {
  552.         for (cis = ci + total; ci < cis; ci++)
  553.           {
  554.               ++(hist[3][r[*ci]]);
  555.           }
  556.         }
  557.       else
  558.         {
  559.         for (cis = ci + total; ci < cis; ci++)
  560.           {
  561.               ++(hist[0][r[*ci]]);
  562.               ++(hist[1][g[*ci]]);
  563.               ++(hist[2][b[*ci]]);
  564.               ++(hist[3][RGB2GRAY(r[*ci], g[*ci], b[*ci])]);
  565.           }
  566.         }
  567.       }
  568.  
  569.     if (IS_GRAY(im))
  570.       {
  571.       if (memcpy(hist[0], hist[3], sizeof(Hist_t)) == 0 ||
  572.           memcpy(hist[1], hist[3], sizeof(Hist_t)) == 0 ||
  573.           memcpy(hist[2], hist[3], sizeof(Hist_t)) == 0)
  574.         {
  575.         Bark("Histogram", "memcpy failed");
  576.         return -1;
  577.         }
  578.       }
  579.     /* get peak value and average */
  580.     for (j = 0; j < 4; j++)
  581.       {
  582.       ave[j] = 0.0;
  583.       hist[j][PCMAX] = 0.0;
  584.       for (i = 0; i < PCMAX; i++)
  585.         {
  586.         if (hist[j][i] > hist[j][PCMAX])
  587.           {
  588.               hist[j][PCMAX] = hist[j][i];
  589.               hist[j][PCMAX + 2] = i;
  590.           }
  591.         ave[j] += hist[j][i] * i;
  592.         }
  593.       hist[j][PCMAX + 1] = (ave[j] / total);
  594.       }
  595.     end_busy();
  596. #ifdef MTRACE
  597.     M_trace("Histogram", "Exit");
  598. #endif
  599.     return 0;
  600. }
  601.  
  602.  
  603. /******************************************************************
  604.  * modify raster according the input function: f(x) Basically a
  605.  * one-to-one mapping.
  606.  *******************************************************************/
  607.  
  608. void
  609. modify_rgb(register rgba_t *ras, long n, register pc_t *r,
  610.        register pc_t *g, register pc_t *b)
  611. {
  612.     register int rr, gg, bb;
  613.     register rgba_t *rs;
  614.  
  615.     if (r == g)
  616.       {                /* must be grayscale images */
  617.       for (rs = ras + n; ras < rs; ras++)
  618.         {
  619.         rr = *ras & PCMAXV;
  620.         rr = *(r + rr);
  621.         *ras = Pack(rr, rr, rr);
  622.         }
  623.       }
  624.     else
  625.       {
  626.       for (rs = ras + n; ras < rs; ras++)
  627.         {
  628.         Unpack(*ras, rr, gg, bb);
  629.         rr = r[rr];
  630.         gg = g[gg];
  631.         bb = b[bb];
  632.         *ras = Pack(rr, gg, bb);
  633.         }
  634.       }
  635. }
  636.  
  637. void
  638. modify_cpack_pixel(register rgba_t *ras, long total,
  639.            register rgba_t old, register rgba_t new,
  640.            register int sw)
  641. {
  642.     register rgba_t *ra;
  643.     for (ra = ras + total; ras < ra; ras++)
  644.       {
  645.       if (*ras == old)
  646.           *ras = new;
  647.       else if (sw && (*ras == new))
  648.           *ras = old;
  649.       }
  650. }
  651.  
  652. /*******************************************************************
  653.  * Modifies all rasters according to mapping given by nlut
  654.  *********************************************************************/
  655. void
  656. modify_all_ci(register ci_t *ras, long total, register ci_t *nlut)
  657. {
  658.     register ci_t *ra = ras + total;
  659.  
  660.     for (; ras < ra; ras++)
  661.     *ras = nlut[*ras];
  662. }
  663.  
  664. /***********************************************************************
  665.  * this can be written as special case of modify_all_ci with 2 entris
  666.  * that are not null transformations lut[i] == i.
  667.  * But for simple swap, this is faster.
  668.  ********************************************************************/
  669. void
  670. modify_ci_pixel(register ci_t *ras, long total,
  671.         register ci_t old, register ci_t new, register int sw)
  672. {
  673.     register ci_t *ra = ras + total;
  674.     for (; ras < ra; ras++)
  675.       {
  676.       if (*ras == old)
  677.           *ras = new;
  678.       else if (sw && *ras == new)
  679.           *ras = old;
  680.       }
  681. }
  682.  
  683. /* **************************************************************
  684.  * replace all pixels that have oldp with newp. If sw is true
  685.  * switch old and new
  686.  ******************************************************************/
  687. void
  688. img_modify_pixel(IPTR im, int oldp[], int newp[], int sw)
  689. {
  690.  
  691.     show_busy("");
  692.  
  693.     if (IS_CPACK(im))
  694.       {
  695.       modify_cpack_pixel(im->raster, im->w * im->h,
  696.                  Pack(oldp[0], oldp[1], oldp[2]),
  697.                  Pack(newp[0], newp[1], newp[2]), sw);
  698.       }
  699.     else
  700.       {
  701.       modify_ci_pixel(im->raster, im->w * im->h,
  702.               oldp[3], newp[3], sw);
  703.       }
  704.     end_busy();
  705. }
  706.  
  707. /***************************************************************
  708.  * Colormap routines
  709.  ***************************************************************/
  710.  
  711. void
  712. set_colmap(int n, pc_t *r, pc_t *g, pc_t *b)
  713. {
  714.     register int i;
  715.  
  716.     for (i = 0; i < n; i++, r++, g++, b++)
  717.     mapcolor(i, *r, *g, *b);
  718. }
  719.  
  720. void
  721. set_cmap(CMPTR m)
  722. {
  723.     set_colmap(m->colors, m->ct[0], m->ct[1], m->ct[2]);
  724. }
  725.  
  726. void
  727. get_colmap(int n, pc_t *r, pc_t *g, pc_t *b)
  728. {
  729.     register int i;
  730.     short x, y, z;
  731.  
  732.     for (i = 0; i < n; i++, *r++ = x, *g++ = y, *b++ = z)
  733.     getmcolor(i, &x, &y, &z);
  734. }
  735.  
  736. void
  737. set_cmap_entry(CMPTR m, int fc[], int ci)
  738. {
  739.     int i;
  740.  
  741.     if (ci >= MAXCML)
  742.       {
  743.       M_warn("SetCmapEntry", "Bad input");
  744.       return;
  745.       }
  746.     for (i = 0; i < 3; i++)
  747.     m->ct[i][ci] = fc[i];
  748.     m->packed = 0;
  749. }
  750.  
  751. void
  752. get_cmap_entry(CMPTR m, int fc[], int ci)
  753. {
  754.     int i;
  755.  
  756.     if (ci >= MAXCML)
  757.       {
  758.       M_warn("GetCmapEntry", "Bad input");
  759.       ci = 0;
  760.       }
  761.     for (i = 0; i < 3; i++)
  762.     fc[i] = m->ct[i][ci];
  763. }
  764.  
  765. /*
  766.  * modify a colormap
  767.  */
  768. void
  769. modify_cmap(CMPTR m, pc_t *r, pc_t *g, pc_t *b)
  770. {
  771.     register pc_t *pc1 = m->ct[0], *pc2 = m->ct[1], *pc3 = m->ct[2];
  772.     register pc_t *pcs;
  773.  
  774.     for (pcs = pc1 + m->colors; pc1 < pcs; pc1++, pc2++, pc3++)
  775.       {
  776.       *pc1 = r[*pc1];
  777.       *pc2 = g[*pc2];
  778.       *pc3 = b[*pc3];
  779.       }
  780.     m->packed = 0;
  781. }
  782.  
  783. void
  784. pack_cmap(CMPTR m)
  785. {
  786.     register pc_t *r = m->ct[0], *g = m->ct[1], *b = m->ct[2];
  787.     register pc_t *rs;
  788.     register rgba_t *rgba = m->p_h.rgba;
  789.  
  790.     if (m->packed > 0)
  791.     return;
  792.  
  793.     for (rs = r + m->colors; r < rs; r++, g++, b++, rgba++)
  794.     *rgba = Pack(*r, *g, *b);
  795.     m->packed = 1;
  796. }
  797.  
  798. void
  799. pack_cmap_g(CMPTR m)
  800. {
  801.     register pc_t *r = m->ct[0], *g = m->ct[1], *b = m->ct[2];
  802.     register pc_t *gr = m->ct[3], *rs;
  803.  
  804.     for (rs = r + m->colors; r < rs; r++, g++, b++, gr++)
  805.     *gr = RGB2GRAY(*r, *g, *b);
  806. }
  807.  
  808. /* find out the no. of uniq colors in a colormap */
  809. int
  810. cmap_ucolors(register CMPTR m, register pc_t *lut)
  811. {
  812.     register int i, j, k;
  813.  
  814.     for (i = k = 0; i < m->colors; i++)
  815.     lut[i] = i;
  816.  
  817.     pack_cmap(m);
  818.  
  819.     for (i = 0; i < m->colors; i++)
  820.       {
  821.       for (j = i + 1; j < m->colors; j++)
  822.         {
  823.         if (lut[j] == j && (m->p_h.rgba[i] == m->p_h.rgba[j]))
  824.           {
  825.               lut[j] = lut[i];
  826.               k++;
  827.           }
  828.         }
  829.       }
  830.  
  831.     return m->ucolors = m->colors - k;
  832. }
  833.  
  834. /********************************************************************
  835.  * Remove redundant entries from colormap and their index from image.
  836.  * Further squeeze is possible if we actually check if all entries in
  837.  * the map are actually used by examing the histograms
  838.  *********************************************************************/
  839.  
  840. void
  841. squeeze_image(IPTR im)
  842. {
  843.     pc_t lutable[PCMAX];
  844.     register CMPTR m = im->cmap;
  845.     register pc_t *lut = lutable;
  846.     register int i, j, k = 0;
  847.  
  848.     /*
  849.      * cmap_ucolors will return a lookup table with entries lut[m] = n; with
  850.      * m > n, meaning mth entry is not unique, and is the same as nth entry.
  851.      * Also only worthwhiel to squeeze if we can save at least 1bit
  852.      */
  853.  
  854.     if ((i = cmap_ucolors(m, lut)) <= m->colors / 2)
  855.       {
  856.       int tnlut[PCMAX];
  857.       register ci_t *ci = im->raster, *cis;
  858.       register CMPTR mm = get_mem_cmap();
  859.       register int *nlut = tnlut;
  860.  
  861.       mm->ct[0][0] = m->ct[0][0];
  862.       mm->ct[1][0] = m->ct[1][0];
  863.       mm->ct[2][0] = m->ct[2][0];
  864.  
  865.       nlut[k++] = 0;
  866.  
  867.       for (i = 1; i < m->colors; i++)
  868.         {
  869.  
  870.         j = lut[i];
  871.  
  872.         if (j == i)    /* uniq */
  873.           {
  874.               mm->ct[0][k] = m->ct[0][i];
  875.               mm->ct[1][k] = m->ct[1][i];
  876.               mm->ct[2][k] = m->ct[2][i];
  877.               nlut[i] = k++;
  878.           }
  879.         else
  880.           {
  881.               /* redundant, and j is smaller than i */
  882.               nlut[i] = nlut[j];
  883.           }
  884.         }
  885.  
  886.       if (k != m->ucolors)
  887.         {
  888.         Bark("Squeeze", "Something is wrong %d %d", k, m->ucolors);
  889.         free_mem_cmap(mm);
  890.         return;
  891.         }
  892.  
  893. #ifdef MDEBUG
  894.       for (i = 0; i < m->colors; i++)
  895.           M_debug("Squeeze", "lut[%d]=%d nlut=%d\n", i, lut[i], nlut[i]);
  896. #endif
  897.  
  898.       /* change the index */
  899.       for (cis = ci + im->w * im->h; ci < cis; ci++)
  900.           *ci = nlut[*ci];
  901.  
  902.       im->colors = mm->colors = mm->ucolors = m->ucolors;
  903.       im->cmap = mm;
  904.       im->cmap->packed = 0;
  905.       free_mem_cmap(m);
  906.  
  907.       im->io->display(im, 0, 0);
  908.       }
  909.  
  910.     update_color_info(im);
  911. }
  912.  
  913. /* this one should be completely rewritten */
  914. int
  915. cmap_closematch(CMPTR m, int r, int g, int b)
  916. {
  917.     register int dr, dg, db;
  918.     register unsigned long mindiff, cdiff;
  919.     register int ci = 0, i;
  920.  
  921.     mindiff = ~0;
  922.     for (i = 0; i < m->colors; i++)
  923.       {
  924.       dr = r - m->ct[0][i];
  925.       dg = g - m->ct[1][i];
  926.       db = b - m->ct[2][i];
  927.       cdiff = (3 * (dr * dr) + 4 * (dg * dg) + 2 * (db * db));
  928.  
  929.       if (cdiff < mindiff)
  930.         {
  931.         mindiff = cdiff;
  932.         ci = i;
  933.         }
  934.  
  935.       /* special provision for exact match */
  936.       if (cdiff == 0)
  937.           goto exact;
  938.       }
  939.   exact:
  940.     return ci;
  941. }
  942.  
  943. /*****************************************************************
  944.  * need to save the original colormap when program starts and
  945.  * re-install the map when program quits. MAXMAP is 4096, but only
  946.  * need to save and restore the map entries used (0--MAXCML)
  947.  *****************************************************************/
  948.  
  949. #define MAXMAP     MAXCML
  950.  
  951. static pc_t sysmap[3][MAXMAP];
  952. static int sysmap_ok;
  953.  
  954. void
  955. get_sysmap(void)
  956. {
  957.     long win;
  958.  
  959.     noport();
  960.     win = winopen("");
  961.     get_colmap(MAXMAP, sysmap[0], sysmap[1], sysmap[2]);
  962.     winclose(win);
  963.     sysmap_ok = 1;
  964. }
  965.  
  966.  
  967. void
  968. set_sysmap(int p)
  969. {
  970.     long win;
  971.  
  972.     if (sysmap_ok)
  973.       {
  974.       noport();
  975.       win = winopen("");
  976.       set_colmap(MAXMAP, sysmap[0], sysmap[1], sysmap[2]);
  977.       winclose(win);
  978.       }
  979.  
  980.     if (p)
  981.     print_before_exit();
  982. }
  983.  
  984. /*********************************************************************
  985.  * get a rectangular piece of image. (x,y) is the screen location
  986.  * directly comparable to im->xi and im->yi, i.e., it is relative
  987.  * to window
  988.  ********************************************************************/
  989.  
  990. void *
  991. get_subimage(IPTR im, int x, int y, int w, int h)
  992. {
  993.     const char *fn = "Get_subimage";
  994.  
  995.     if (!image_ready(im, fn))
  996.     return 0;
  997.  
  998.     if (x < im->xi || y < im->yi || h <= 0 || w <= 0 ||
  999.     (x + w - 1) > im->xf || (y + h - 1) > im->yf)
  1000.       {
  1001.       Bark(fn, "Bad requested region");
  1002.       return 0;
  1003.       }
  1004.  
  1005.     /* now everything is ok. Do it */
  1006.     return get_submat(im->mraster, im->h, im->w,
  1007.               y - im->yi, x - im->xi, h, w, im->esize);
  1008. }
  1009.  
  1010. /*********************************************************************
  1011.  * Similar to get_subimage, but will never fail: if requested
  1012.  * region is outside the image, it will be filled by whatever
  1013.  * in the framebuffer. It will fail, however, if illogical
  1014.  * value such as w < 0 || h < 0 is passed
  1015.  **********************************************************************/
  1016.  
  1017. void *
  1018. no_fail_get_subimage(IPTR im, int x, int y, int w, int h)
  1019. {
  1020.     char **ret;
  1021.  
  1022.     if (w <= 0 || h <= 0)
  1023.       {
  1024.       Bark("NoFailGetSubImage", "bad w and/or h");
  1025.       return 0;
  1026.       }
  1027.  
  1028.     if (x < im->xi || y < im->yi ||
  1029.     (x + w - 1) > im->xf || (y + h - 1) > im->yf)
  1030.       {
  1031.       int ux, uy, uw, uh;
  1032.       rgba_t fillc = (IS_CPACK(imgptr) ? background_color : BKINDEX);
  1033.  
  1034.       ret = get_mat(h, w, im->esize);
  1035.  
  1036.       /* initialize it to background color */
  1037.       init_mat(ret, h, w, im->esize, fillc);
  1038.  
  1039.       /* need to replace the union with the piece from raster */
  1040.       ux = Max(im->xi, x);
  1041.       uy = Max(im->yi, y);
  1042.  
  1043.       uw = Min(im->xf, (x + w - 1)) - ux + 1;
  1044.       uh = Min(im->yf, (y + h - 1)) - uy + 1;
  1045.  
  1046.       if (uw > 0 && uh > 0)    /* union exists */
  1047.         {
  1048.         void *p = get_subimage(im, ux, uy, uw, uh);
  1049.         int oop = get_mat_op();
  1050.  
  1051.         /* Insert sm into framebuffer matrix. Always in NOOP mode */
  1052.         set_mat_op(O_NONE);
  1053.         put_submat(ret, h, w, p,
  1054.                uy - y, ux - x, uh, uw, im->esize);
  1055.         set_mat_op(oop);
  1056.         free_mat(p);
  1057.         }
  1058.       }
  1059.     else
  1060.       {
  1061.       /* within image */
  1062.       ret = get_subimage(im, x, y, w, h);
  1063.       }
  1064.     return ret;
  1065. }
  1066.  
  1067. int
  1068. put_subimage(IPTR im, void *m, const Rect_t * r, int warn)
  1069. {
  1070.     static const char *fn = "PutSubImage";
  1071.     const Rect_t *o;
  1072.     void *sm;
  1073.  
  1074.     if (!image_ready(im, fn))
  1075.     return -1;
  1076.  
  1077.     if (!(o = union_rect(r, img_rect(im))))
  1078.       {
  1079.       if (warn)
  1080.           Bark(fn, "Bad requested region");
  1081.       return -1;
  1082.       }
  1083.  
  1084.     if (equal_rect(r, o))
  1085.       {
  1086.       return put_submat(im->mraster, im->h, im->w,
  1087.             m, r->y - im->yi, r->x - im->xi, r->h, r->w, im->esize);
  1088.       }
  1089.  
  1090.     /* clip */
  1091.     sm = get_submat(m, r->h, r->w,
  1092.             o->y - r->y, o->x - r->x, o->h, o->w, im->esize);
  1093.     put_submat(im->mraster, im->h, im->w, sm,
  1094.            o->y - im->yi, o->x - im->xi, o->h, o->w, im->esize);
  1095.     free_mat(sm);
  1096.     return 0;
  1097. }
  1098.  
  1099.  
  1100. /***********************************************************************
  1101.  * given several keys, say ppm, pgm and pbm, check if any of the keys has
  1102.  * the same type as the current image, if there is, return the index into
  1103.  * the img_io, else if no match can be found, return the first match.
  1104.  * Therefore, the caller should always place the keys in decreasing order
  1105.  * in generality, i.e, ppm, pgm and pbm, NEVER pbm, pgm and ppm
  1106.  **********************************************************************/
  1107. int
  1108. best_format(IPTR im, char *const *keys)
  1109. {
  1110.     char *const *q = keys;
  1111.     int i, first = -1;
  1112.     int bestsofar = totalfmt + 1;    /* negative match, positive best */
  1113.     int best;
  1114.  
  1115.     if (!*q || !im->ok)
  1116.       {
  1117.  
  1118. #ifdef MDEBUG
  1119.       M_debug("BestFmt", "Bad input");
  1120. #endif
  1121.       return -1;
  1122.       }
  1123.  
  1124.  
  1125.     do
  1126.       {
  1127.       /* go thru all images and check for key match */
  1128.       for (i = 0; i < totalfmt && strcasecmp(img_io[i].key, *q); i++)
  1129.           ;
  1130.  
  1131.       /* we have found a match at i, check if type OK */
  1132.       if (i < totalfmt)
  1133.         {            /* match */
  1134.         bestsofar = (im->type == img_io[i].type ||
  1135.                  img_io[i].type == T_FLEX) ? i : -i;
  1136.  
  1137.         /* remember the first match */
  1138.         if (first < 0)
  1139.             first = i;    /* first match */
  1140.         }
  1141.  
  1142. #ifdef MDEBUG
  1143.       else
  1144.         {
  1145.         M_debug("BestFmt", "%s not found", *q);
  1146.         }
  1147. #endif
  1148.  
  1149.       }
  1150.     while (*++q && (bestsofar < 0 || bestsofar > totalfmt));
  1151.  
  1152.     /* the best one */
  1153.     best = (bestsofar > totalfmt) ? -1 : (bestsofar >= 0 ? bestsofar : first);
  1154.  
  1155.     M_info("BestFmt", "1stReq %s, Best %s",
  1156.        keys[0], (best >= 0) ? img_io[best].key : "none");
  1157.  
  1158.     return best;
  1159. }
  1160.  
  1161. /***********************************************************************
  1162.  * image type conversions
  1163.  * quantization is in a separate file due to its size
  1164.  ***********************************************************************/
  1165.  
  1166. #include "lookup.h"        /* lookup tables */
  1167.  
  1168. /**** given RGB, get the packed pixel for display *****/
  1169. static void
  1170. rgb_to_cpack(register rgba_t *p, register pc_t *r,
  1171.          register pc_t *g, register pc_t *b, long sz)
  1172. {
  1173.     register pc_t *rs;
  1174.  
  1175.     if (r == g)
  1176.       {                /* grayscale */
  1177.       for (rs = r + sz; r < rs; r++)
  1178.           *p++ = Pack(*r, *r, *r);
  1179.       }
  1180.     else
  1181.       {
  1182.       for (rs = r + sz; r < rs; r++, g++, b++)
  1183.           *p++ = Pack(*r, *g, *b);
  1184.       }
  1185. }
  1186.  
  1187. int
  1188. img_rgb_to_cpack(IPTR im)
  1189. {
  1190.     register pc_t *r, *g, *b;
  1191.     register long total = im->h * im->w;
  1192.  
  1193.     if (!im->pc[0])
  1194.       {
  1195.       Bark("Packing", "Bad RGB matrix");
  1196.       return -1;
  1197.       }
  1198.  
  1199.     r = im->pc[0][0];
  1200.     g = im->pc[1][0];
  1201.     b = im->pc[2][0];
  1202.  
  1203.     im->type = (IS_GRAY(im) || r == g) ? T_GRAY : T_RGBA;
  1204.  
  1205.     if (img_get_rastermem(im) >= 0)
  1206.       {
  1207.       if (im->type == T_RGBA)
  1208.         {
  1209.         rgb_to_cpack(im->raster, r, g, b, total);
  1210.         }
  1211.       else
  1212.         {
  1213.         rgb_to_cpack(im->raster, r, r, r, total);
  1214.         }
  1215.       im->ok = 1;
  1216.       }
  1217.  
  1218.     return im->ok ? 0 : -1;
  1219. }
  1220.  
  1221. /******* given a cpack, take it apart to get RGB *******/
  1222. static int
  1223. cpack_to_rgb(IPTR im)
  1224. {
  1225.     register pc_t *r, *g, *b;
  1226.     register rgba_t *rgba, *rs;
  1227.     register int total = im->w * im->h;
  1228.     int status;
  1229.  
  1230.     if ((status = img_get_rgbmem(im)) >= 0)
  1231.       {
  1232.       rgba = im->raster;
  1233.       r = im->pc[0][0];
  1234.       g = im->pc[1][0];
  1235.       b = im->pc[2][0];
  1236.       for (rs = rgba + total; rgba < rs; r++, g++, b++, rgba++)
  1237.         {
  1238.         CPACK2RGB(*rgba, *r, *g, *b);
  1239.         }
  1240.       }
  1241.     return status;
  1242. }
  1243.  
  1244. /******** given a cmap img, get RGB triplets *********/
  1245. static int
  1246. cmap_to_rgb(IPTR im)
  1247. {
  1248.     register pc_t *r, *g, *b;
  1249.     register pc_t *mr, *mg, *mb;
  1250.     register ci_t *ras = im->raster, *rs;
  1251.     register int total = im->w * im->h;
  1252.     int status;
  1253.  
  1254.     if ((status = img_get_rgbmem(im)) >= 0)
  1255.       {
  1256.       mr = im->cmap->ct[0];
  1257.       mg = im->cmap->ct[1];
  1258.       mb = im->cmap->ct[2];
  1259.       r = im->pc[0][0];
  1260.       g = im->pc[1][0];
  1261.       b = im->pc[2][0];
  1262.       for (rs = ras + total; ras < rs; ras++)
  1263.         {
  1264.         *r++ = mr[*ras];
  1265.         *g++ = mg[*ras];
  1266.         *b++ = mb[*ras];
  1267.         }
  1268.       }
  1269.     else
  1270.       {
  1271.       Bark("cmap2cpack", mfailed);
  1272.       }
  1273.     return status;
  1274. }
  1275.  
  1276. /***** get RGB triplets from an image *****/
  1277.  
  1278. int
  1279. img_get_rgb(IPTR im)
  1280. {
  1281.     return (!im || !im->raster) ? -1 :
  1282.     (IS_CI(im) ? cmap_to_rgb : cpack_to_rgb) (im);
  1283. }
  1284.  
  1285. /***** fill some fields of image structure ******/
  1286.  
  1287. int
  1288. fill_image_struct(IPTR im, void *m, int h, int w, IMG_TYPE t)
  1289. {
  1290.     if (!m || w < 1 || h < 1)
  1291.       {
  1292.       M_err("ImageFill", "Bad input");
  1293.       return -1;
  1294.       }
  1295.  
  1296.     /*
  1297.      * need to make sure m and im->mraster are different before messing with
  1298.      * im->mraster
  1299.      */
  1300.     if (im->mraster != m)
  1301.     img_free_rastermem(im);
  1302.  
  1303.     im->w = w;
  1304.     im->h = h;
  1305.     im->mraster = m;
  1306.     im->raster = ((char **) m)[0];
  1307.  
  1308.     /* get the pixel size */
  1309.     if (t == T_CMAP)
  1310.     im->esize = sizeof(ci_t);
  1311.     else if (t == T_GRAY)
  1312.     im->esize = sizeof(gray_t);
  1313.     else if (t == T_RGBA)
  1314.     im->esize = sizeof(rgba_t);
  1315.     else if (t == T_GMAP)
  1316.     im->esize = sizeof(ci_t);
  1317.     else if (t == T_BW)
  1318.     im->esize = sizeof(bw_t);
  1319.     else
  1320.     return -1;
  1321.  
  1322.     im->size = im->esize * w * h;
  1323.     im->ok = 1;
  1324.     im->type = t;
  1325.     update_image_info(im);
  1326.     return 0;
  1327. }
  1328.  
  1329. /** Create an image of solid colors *********/
  1330. IPTR
  1331. create_image(const char *name, int type, int w, int h, rgba_t col)
  1332. {
  1333.     IPTR im;
  1334.  
  1335.     if (w <= 0 || h <= 0)
  1336.       {
  1337.       M_err("ImageCreate", "Bad arg w=%d h=%d\n", w, h);
  1338.       return 0;
  1339.       }
  1340.  
  1341.     (im = get_mem_imgptr())->cmap = get_mem_cmap();
  1342.     im->type = type;
  1343.     im->w = w;
  1344.     im->h = h;
  1345.  
  1346.     /* fill the raster */
  1347.     img_get_rastermem(im);
  1348.     init_mat(im->mraster, im->h, im->w, im->esize, col);
  1349.  
  1350.     im->ok = 1;
  1351.  
  1352.     strcpy(im->ifile, (name && *name) ? name : "untitled");
  1353.     im->info = "Internal";
  1354.     im->key = "?";
  1355.  
  1356.     im->io = &img_io[0];
  1357.     im->io->display = Generic_display;
  1358.     return im;
  1359. }
  1360.  
  1361. /********************************************************************
  1362.  * Convert from colormapped image to RGBA
  1363.  *
  1364.  * the mask is important since the mapped image might be a result of
  1365.  * screen read and if writemask is not set properly (not set at all
  1366.  * at this moment), the index will be full 12bits. Only the bits
  1367.  * with mask are meaningful
  1368.  **********************************************************************/
  1369.  
  1370. static int
  1371. cmap_to_cpack(IPTR im)
  1372. {
  1373.     /*
  1374.      * can't simply use no. of colors as masks because it might not be 2^n,
  1375.      * e.g., sunraster file
  1376.      */
  1377.     int p = power_of_2(im->cmap->colors);
  1378.     register ci_t mask = (p > MAXCML ? MAXCML : p) - 1;
  1379.     register ci_t *ci = im->raster, *cis;
  1380.     register rgba_t *ras, *mp, **m;
  1381.  
  1382.     if (!(m = get_mat(im->h, im->w, sizeof(rgba_t))))
  1383.       {
  1384.       Bark("CmapToCpack", mfailed);
  1385.       return -1;
  1386.       }
  1387.     pack_cmap(im->cmap);
  1388.     mp = im->cmap->p_h.rgba;
  1389.     ras = m[0];
  1390.  
  1391.     for (cis = ci + im->h * im->w; ci < cis; ci++, ras++)
  1392.     *ras = *(mp + ((*ci) & mask));
  1393.     return fill_image_struct(im, m, im->h, im->w,
  1394.           ((im->type == T_GMAP || im->type == T_BW) ? T_GRAY : T_RGBA));
  1395. }
  1396.  
  1397. /***** convert from RGBA to grayscale ****/
  1398. int
  1399. rgb2gray(int r, int g, int b)
  1400. {
  1401.     return RGB2GRAY(r, g, b);
  1402. }
  1403.  
  1404. int
  1405. cpack2gray(rgba_t c)
  1406. {
  1407.     return CPACK2GRAY(c);
  1408. }
  1409.  
  1410. static int
  1411. cpack_to_gray(IPTR im)
  1412. {
  1413.     register rgba_t *p = im->raster, *ps;
  1414.     int total = im->w * im->h;
  1415.  
  1416.     if (!IS_RGBGRAY(im))
  1417.       {
  1418.       for (ps = p + total; p < ps; p++)
  1419.         {
  1420.         *p = CPACK2GRAY(*p);
  1421.         *p = RGB2CPACK(*p, *p, *p);
  1422.         }
  1423.       im->type = T_GRAY;
  1424.       }
  1425.     return 0;
  1426. }
  1427.  
  1428. /***** map based grayscale will turn into T_GMAP ****/
  1429.  
  1430. static int
  1431. cmap_to_mgray(IPTR im)
  1432. {
  1433.     register rgba_t p;
  1434.     register pc_t *r = im->cmap->ct[0], *rs;
  1435.     register pc_t *g = im->cmap->ct[1];
  1436.     register pc_t *b = im->cmap->ct[2];
  1437.  
  1438.     if (!IS_MGRAY(im))
  1439.       {
  1440.       for (rs = r + im->cmap->colors; r < rs; r++, g++, b++)
  1441.         {
  1442.         p = RGB2GRAY(*r, *g, *b);
  1443.         *r = *g = *b = (pc_t) p;
  1444.         }
  1445.       im->cmap->packed = 0;    /* very important */
  1446.       im->type = T_GMAP;
  1447.       }
  1448.     return 0;
  1449. }
  1450.  
  1451. static int
  1452. cmap_to_gray(IPTR im)
  1453. {
  1454.     return (cmap_to_mgray(im) < 0 || cmap_to_cpack(im) < 0) ? -1 : 0;
  1455. }
  1456.  
  1457. #if 0                /*** {***/
  1458. int
  1459. img_to_gray(IPTR im)
  1460. {
  1461.     int status;
  1462.  
  1463.     if (!im || !im->raster)
  1464.     return -1;
  1465.  
  1466.     if (IS_GRAY(im))
  1467.     return 0;
  1468.     status = (IS_CPACK(im)) ?
  1469.     cpack_to_gray(im) : cmap_to_mgray(im);
  1470.     text_to_gray();
  1471.     sgf_to_gray();
  1472.     update_image_info(im);
  1473.     return status;
  1474. }
  1475. #endif /****}**/
  1476.  
  1477. /* ARGSUSED */
  1478. static int
  1479. noop(IPTR im)
  1480. {
  1481.     return 0;
  1482. }
  1483.  
  1484. static int
  1485. cpack_to_gmap(IPTR im)
  1486. {
  1487.     return (cpack_to_gray(im) < 0 || rgb_to_cmap(im) < 0) ? -1 : 0;
  1488. }
  1489.  
  1490.  
  1491. static int
  1492. cpack_to_bw(IPTR im)
  1493. {
  1494.     return img_half_toning(im);
  1495. }
  1496.  
  1497. /********* convert to cpack and then to B&W **************/
  1498.  
  1499. static int
  1500. cmap_to_bw(IPTR im)
  1501. {
  1502.     return (cmap_to_cpack(im) >= 0) ? cpack_to_bw(im) : -1;
  1503. }
  1504.  
  1505. /******************************************************
  1506.  * Global interface to convert image types
  1507.  *
  1508.  ******************************************************/
  1509.  
  1510. /*
  1511.  * Set up the type conversion matrix, with proper provisions for T_FLEX and
  1512.  * other types, then everything is reduced to a table lookup
  1513.  */
  1514.  
  1515. typedef int (*fcnvt) (IPTR);
  1516. typedef int (*fprecnvt) (void);
  1517.  
  1518. typedef struct
  1519.   {
  1520.       IMG_TYPE from, to;    /* image types */
  1521.       fprecnvt precnvt;        /* if preparation is needed */
  1522.       fcnvt cnvt;        /* do it */
  1523.   } convt_s;
  1524.  
  1525. static convt_s conv[] =
  1526. {
  1527.  
  1528. /* start with colormapped images */
  1529.     {T_CMAP, T_RGBA, 0, cmap_to_cpack},
  1530.     {T_CMAP, T_GMAP, 0, cmap_to_mgray},
  1531.     {T_CMAP, T_GRAY, 0, cmap_to_gray},
  1532.     {T_CMAP, T_BW, pre_bw, cmap_to_bw},
  1533.     {T_CMAP, T_RGB, 0, cmap_to_rgb},
  1534.  
  1535. /* start with graymap images */
  1536.     {T_GMAP, T_GRAY, 0, cmap_to_cpack},
  1537.     {T_GMAP, T_RGBA, 0, cmap_to_cpack},
  1538.     {T_GMAP, T_BW, pre_bw, cmap_to_bw},
  1539.     {T_GMAP, T_CMAP, 0, noop},
  1540.     {T_GMAP, T_RGB, 0, cmap_to_rgb},
  1541.  
  1542. /* start with cpack   */
  1543.     {T_RGBA, T_GRAY, 0, cpack_to_gray},
  1544.     {T_RGBA, T_CMAP, pre_quant, rgb_to_cmap},
  1545.     {T_RGBA, T_GMAP, pre_quant, cpack_to_gmap},
  1546.     {T_RGBA, T_BW, pre_bw, cpack_to_bw},
  1547.     {T_RGBA, T_RGB, 0, cpack_to_rgb},
  1548.  
  1549. /* start with RGBA gray */
  1550.     {T_GRAY, T_RGBA, 0, noop},
  1551.     {T_GRAY, T_GMAP, pre_quant, rgb_to_cmap},
  1552.     {T_GRAY, T_CMAP, pre_quant, rgb_to_cmap},
  1553.     {T_GRAY, T_BW, pre_bw, cpack_to_bw},
  1554.  
  1555. /* start with B&W */
  1556.     {T_BW, T_GMAP, 0, noop},
  1557.     {T_BW, T_CMAP, 0, noop},
  1558.     {T_BW, T_GRAY, 0, cmap_to_cpack},
  1559.     {T_BW, T_RGBA, 0, cmap_to_cpack},
  1560. /* sentinels */
  1561.     {T_INVALID, T_INVALID, 0}
  1562. };
  1563.  
  1564. int
  1565. img_convert_type(IPTR im, IMG_TYPE newtype)
  1566. {
  1567.     register int found;
  1568.     register convt_s *p;
  1569.     int cancel = 0;
  1570.  
  1571.  
  1572.     if (!im || !im->raster)
  1573.       {
  1574.       Bark("TypeConvert", "Bogus input");
  1575.       return -1;
  1576.       }
  1577.  
  1578.     /* check for special cases: A Flex type means any type is ok */
  1579.     if (newtype == T_FLEX || im->type == newtype)
  1580.     return 0;
  1581.  
  1582.     /* we'll be generating new colormaps */
  1583.     if (newtype == T_CMAP || newtype == T_GMAP)
  1584.     im->cmap->packed = 0;
  1585.  
  1586.     /* get the appropriate function */
  1587.     for (p = &conv[0], found = 0; !found && p->from != T_INVALID; p++)
  1588.     found = p->from == im->type && p->to == newtype;
  1589.  
  1590.     if (!found)
  1591.       {
  1592.       to_be_written("ConvertType");
  1593.       return 1;
  1594.       }
  1595.  
  1596.     /* last chance to back off, indicated by cancel */
  1597.     if ((--p)->precnvt)
  1598.     cancel = p->precnvt();
  1599.  
  1600.     return cancel ? -1 : p->cnvt(im);
  1601. }
  1602.  
  1603. /**************************************************************
  1604.  * switch black and white: special service to all bw images
  1605.  **************************************************************/
  1606.  
  1607. void
  1608. bw_special(IPTR im)
  1609. {
  1610.     register pc_t b;
  1611.     register CMPTR m = im->cmap;
  1612.  
  1613.     if (IS_BW(im))
  1614.       {
  1615.       b = m->ct[0][0];
  1616.       m->ct[0][0] = m->ct[1][0] = m->ct[2][0] = m->ct[0][1];
  1617.       m->ct[0][1] = m->ct[1][1] = m->ct[2][1] = b;
  1618.       set_cmap(m);
  1619.       }
  1620. }
  1621.  
  1622. /*****************************************************************
  1623.  * normalize a primary color vector of length n to within
  1624.  * (imin, imax)
  1625.  *******************************************************************/
  1626. void
  1627. normal_pc_vec(pc_t *vec, int n, int imin, int imax)
  1628. {
  1629.     register pc_t *v = vec, *vs;
  1630.     register int vmin, vmax;
  1631.     register float a, b;
  1632.  
  1633.     vmin = vmax = *v;
  1634.  
  1635.     for (vs = v + n; v < vs; v++)
  1636.       {
  1637.       if (vmin > *v)
  1638.           vmin = *v;
  1639.       if (vmax < *v)
  1640.           vmax = *v;
  1641.       }
  1642.  
  1643.     if (imin == vmin && imax == vmax)    /* already normalized */
  1644.     return;
  1645.     if (vmax == vmin)        /* bad stuff */
  1646.     return;
  1647.  
  1648.     a = ((float) imax - imin) / (float) (vmax - vmin);
  1649.     b = imin - a * vmin;
  1650.  
  1651.     for (v = vec; v < vs; v++)
  1652.     *v = ((float) *v * a + b + 0.5);
  1653.     return;
  1654. }
  1655.  
  1656. /* interpolate a primary color vector of n to np */
  1657. void
  1658. interpolate_pc_vec(register pc_t *vin, int n,
  1659.            register pc_t *vout, int np)
  1660. {
  1661.     register float sx, dx, f;
  1662.     int kx, kx1;
  1663.     int i;
  1664.  
  1665.     sx = (float) (n - 1.0) / (np - 1.0);
  1666.     for (i = 0; i < np; i++)
  1667.       {
  1668.       dx = sx * i;
  1669.       kx = dx;
  1670.       dx = dx - kx;
  1671.       kx1 = kx + (kx < n - 1);
  1672.       f = vin[kx];
  1673.       f += dx * (vin[kx1] - f);
  1674.       vout[i] = (f + 0.5);
  1675.       }
  1676.     return;
  1677. }
  1678.  
  1679. /*
  1680.  * Default colormaps for bit in displaying edge maps and other
  1681.  * stuff.
  1682.  */
  1683. typedef struct
  1684. {
  1685.     int n;            /* no. of entries  */
  1686.     pc_t red[PCMAX];
  1687.     pc_t grn[PCMAX];
  1688.     pc_t blue[PCMAX];
  1689.     short pcmin, pcmax;        /* channel range   */
  1690.     short rave, gave, bave;    /* average in map */
  1691. }
  1692. DefMap;
  1693.  
  1694. #define MAXDEFMAP  18
  1695. static DefMap *defmaps[MAXDEFMAP];
  1696. static int nmap;
  1697.  
  1698. static int
  1699. load_defmap_fp(FILE * fp)
  1700. {
  1701.     int done, k, n;
  1702.     register pc_t *r, *g, *b, *rs;
  1703.     register long rave, gave, bave;
  1704.     DefMap *m;
  1705.  
  1706.     k = nmap;
  1707.     do
  1708.       {
  1709.       done = (n = readpint(fp)) < 0;
  1710.       if (!done)
  1711.         {
  1712.         m = defmaps[k] = malloc(sizeof(*defmaps[0]));
  1713.         m->n = n;
  1714.         m->pcmin = readpint(fp);
  1715.         m->pcmax = readpint(fp);
  1716.         r = m->red;
  1717.         g = m->grn;
  1718.         b = m->blue;
  1719.         rave = gave = bave = 0;
  1720.         for (rs = r + n; r < rs; r++, g++, b++)
  1721.           {
  1722.               rave += (*r = readpint(fp));
  1723.               gave += (*g = readpint(fp));
  1724.               bave += (*b = readpint(fp));
  1725.           }
  1726.         m->rave = rave / n;
  1727.         m->gave = gave / n;
  1728.         m->bave = bave / n;
  1729.         ++k;
  1730.         }
  1731.       }
  1732.     while (!done);
  1733.     return k - nmap;
  1734. }
  1735.  
  1736. static int
  1737. load_defmap(void)
  1738. {
  1739.     static const char *mapfile = "defmap.map";
  1740.     FILE *fp;
  1741.     int k = 0;
  1742.  
  1743.     if (nmap > 0)
  1744.     return nmap;
  1745.  
  1746.     /* try system directory first */
  1747.     if ((fp = get_HELPfile_fp(mapfile, "r")))
  1748.       {
  1749.       k = nmap = load_defmap_fp(fp);
  1750.  
  1751. #ifdef MDEBUG
  1752.       M_debug("DefMap", "Got %d maps from SysDir", nmap);
  1753. #endif
  1754.       fclose(fp);
  1755.       }
  1756.  
  1757.     /* user directory */
  1758.     if ((fp = get_BITfile_fp(mapfile, "r")))
  1759.       {
  1760.       k = k + load_defmap_fp(fp);
  1761.  
  1762. #ifdef MDEBUG
  1763.       M_debug("DefMap", "Got %d maps from UserDir", k - nmap);
  1764. #endif
  1765.  
  1766.       nmap = k;
  1767.       fclose(fp);
  1768.       }
  1769.     M_info("LoadDefMap", "Total %d maps found", nmap);
  1770.     return nmap;
  1771. }
  1772.  
  1773. /*
  1774.  * get default map. a zero indicates grayscale map. Colormap so generated
  1775.  * will always have the correct range regardless how many entries are
  1776.  * requested
  1777.  */
  1778. void
  1779. get_bit_defmap(int n, register pc_t *r, register pc_t *g,
  1780.            register pc_t *b, int req)
  1781. {
  1782.     int i;
  1783.     register pc_t *rr, *gg, *bb;
  1784.     DefMap *m;
  1785.  
  1786.     if (!nmap)
  1787.     nmap = load_defmap();
  1788.  
  1789. #ifdef MDEBUG
  1790.     M_debug("DefMap", "Getting %d from total of %d", n, nmap);
  1791. #endif
  1792.  
  1793.     if (n < 0 || n > nmap)
  1794.     n = 0;
  1795.  
  1796.     if (n == 0)
  1797.       {                /* default gray */
  1798.       float a = (float) PCMAXV / req;
  1799.       for (i = 0; i < req; i++, r++, g++, b++)
  1800.           *r = *g = *b = (a * i + 0.5);
  1801.       return;
  1802.       }
  1803.  
  1804.     --n;
  1805.     m = defmaps[n];
  1806.     rr = m->red;
  1807.     gg = m->grn;
  1808.     bb = m->blue;
  1809.  
  1810.     /* check if map is normalized */
  1811.     if ((m->pcmax - PCMAXV) || (m->pcmin != 0))
  1812.       {
  1813.       normal_pc_vec(rr, m->n, 0, PCMAXV);
  1814.       normal_pc_vec(gg, m->n, 0, PCMAXV);
  1815.       normal_pc_vec(bb, m->n, 0, PCMAXV);
  1816.       m->pcmin = 0;
  1817.       m->pcmax = PCMAXV;
  1818.       }
  1819.     /* check if length match */
  1820.     if (req != m->n)
  1821.       {
  1822.       interpolate_pc_vec(rr, m->n, r, req);
  1823.       interpolate_pc_vec(gg, m->n, g, req);
  1824.       interpolate_pc_vec(bb, m->n, b, req);
  1825.  
  1826.       if (req > m->n && req < PCMAX)
  1827.         {
  1828.         memcpy(rr, r, sizeof(pc_t) * req);
  1829.         memcpy(gg, g, sizeof(pc_t) * req);
  1830.         memcpy(bb, b, sizeof(pc_t) * req);
  1831.         m->n = req;
  1832.         }
  1833.       }
  1834.     else
  1835.       {
  1836.       memcpy(r, rr, sizeof(pc_t) * req);
  1837.       memcpy(g, gg, sizeof(pc_t) * req);
  1838.       memcpy(b, bb, sizeof(pc_t) * req);
  1839.       }
  1840.     return;
  1841. }
  1842.  
  1843. int
  1844. get_number_of_defmaps(void)
  1845. {
  1846.     return nmap ? nmap : (nmap = load_defmap());
  1847. }
  1848.  
  1849. /* set format specific info */
  1850. void
  1851. set_iformat_info(IPTR im, const char *s)
  1852. {
  1853.     if (s && im)
  1854.     Strncpy(im->misc, s, MAXINFO - 1);
  1855. }
  1856.  
  1857. /******************************************************************
  1858.  * read a piece of framebuffer and save it to the image in core mem.
  1859.  * Also clip to the edge of the image.
  1860.  *
  1861.  * Due to the way geomtric figure is handled in bit, negative w and/or h
  1862.  * is possible.
  1863.  ******************************************************************/
  1864. void
  1865. fb_to_ras(IPTR im, const Rect_t * r)
  1866. {
  1867.     char **pp;
  1868.     const Rect_t *o, *u;
  1869.     static const char *fn = "FB2RAS";
  1870.     long odraw = getdrawmode();
  1871.     Rect_t tmp;
  1872.  
  1873.  
  1874.     drawmode(NORMALDRAW);
  1875.  
  1876.     /*
  1877.      * read it only if overlap. Also we should not allow the src rectangle to
  1878.      * be outside of the window
  1879.      */
  1880.     copy_rect(&tmp, r);
  1881.     u = union_rect(canonicalize_rect(&tmp), img_rect(im));
  1882.     if (u && (o = union_rect(u, make_rect(0, 0, win_w - 1, win_h - 1))))
  1883.       {
  1884.       Rect_t p;
  1885.       /*
  1886.        * always a good idea to copy the union as other routines might
  1887.        * overwrite the static buffer
  1888.        */
  1889.       copy_rect(&p, o);
  1890.       M_info(fn, "x=%d y=%d w=%d h=%d", p.x, p.y, p.w, p.h);
  1891.       pp = get_mat(p.h, p.w, im->esize);
  1892.       Rectread(p.x, p.y, p.x + p.w - 1, p.y + p.h - 1, pp[0]);
  1893.       put_subimage(im, pp, &p, 0);
  1894.       free_mat(pp);
  1895.       }
  1896.     else
  1897.       {
  1898.       M_info(fn, "no overlap");
  1899.       }
  1900.  
  1901.     drawmode(odraw);
  1902. }
  1903.  
  1904.  
  1905. /*
  1906.  * To minimize interference with window manager, we manipulate the
  1907.  * image so that some of the wm colors are preserved. Different wm
  1908.  * may use different schemes for lut, we will have to give the color
  1909.  * in RGB representation and search the default colormap for the index
  1910.  * For images where index has meaning, e.g., intensity, etc., set
  1911.  * preserve_wm_colors to zero to supress color swapping.
  1912.  */
  1913.  
  1914. typedef struct
  1915. {
  1916.     rgba_t rgba;        /* colors to preserve          */
  1917.     ci_t ci;            /* its index in default sysmap */
  1918. }
  1919.  
  1920. Wmcolor;
  1921.  
  1922. /*
  1923.  * because collision is not taken care of, the colors that must be
  1924.  * preserved should be the last one in table
  1925.  */
  1926. static Wmcolor wmcolor[] =
  1927. {
  1928.     {0x00ffffff, 0},        /* white */
  1929.     {0, 0}            /* black */
  1930. };
  1931.  
  1932. #define SwapMapEntry(m, i, j)                             \
  1933.             do {  int r_, g_, b_;                         \
  1934.                r_ = m->ct[0][i];                          \
  1935.                g_ = m->ct[1][i];                          \
  1936.                b_ = m->ct[2][i];                          \
  1937.                m->ct[0][i] = m->ct[0][j];                 \
  1938.                m->ct[1][i] = m->ct[1][j];                 \
  1939.                m->ct[2][i] = m->ct[2][j];                 \
  1940.                m->ct[0][j] = r_;                          \
  1941.                m->ct[1][j] = g_;                          \
  1942.                m->ct[2][j] = b_;                          \
  1943.             } while (ZERO)
  1944.  
  1945. #define DOGROUP            /* if more than 1 reserved color, define this */
  1946.  
  1947. void
  1948. img_preserve_wm_colors(IPTR im)
  1949. {
  1950.     static int first = 1;
  1951.     int tran;
  1952.     int i, pr, pg, pb, k;
  1953.     int npreserve = sizeof(wmcolor) / sizeof(wmcolor[0]);
  1954.     CMPTR m = im->cmap;
  1955.  
  1956. #ifdef DOGROUP
  1957.     ci_t allt[MAXCML];
  1958.  
  1959.     /* initialize the transformation table */
  1960.     for (i = 0; i < m->colors; i++)
  1961.     allt[i] = i;
  1962. #endif
  1963.  
  1964.     /* search the default system map for black and white */
  1965.     if (first)
  1966.       {
  1967.       int r, g, b;
  1968.       unsigned long mdiff, cdiff;
  1969.       for (k = 0; k < npreserve; k++)
  1970.         {
  1971.         Unpack(wmcolor[k].rgba, pr, pg, pb);
  1972.         mdiff = ~0;
  1973.         for (i = 0; i < 15; i++)
  1974.           {
  1975.               r = (pr - sysmap[0][i]);
  1976.               g = (pg - sysmap[1][i]);
  1977.               b = (pb - sysmap[2][i]);
  1978.               cdiff = 3 * r * r + 4 * g * g + 2 * b * b;
  1979.               if (cdiff < mdiff)
  1980.             {
  1981.                 wmcolor[k].ci = i;
  1982.                 mdiff = cdiff;
  1983.             }
  1984.           }
  1985.         }
  1986.       first = 0;
  1987.       }
  1988.  
  1989.     /*
  1990.      * re-arrange the colormap so that requested colors to be preserved. have
  1991.      * the same index in current map and system map could be slow if
  1992.      * npreserve is large
  1993.      */
  1994.  
  1995.     for (k = 0; k < npreserve; k++)
  1996.       {
  1997.       /*
  1998.        * since we only will use m->colors, there is no point to preserve
  1999.        * colors indeces that are larger than m->colors
  2000.        */
  2001.  
  2002.       if (wmcolor[k].ci >= m->colors)
  2003.           continue;
  2004.  
  2005.       Unpack(wmcolor[k].rgba, pr, pg, pb);
  2006.       tran = cmap_closematch(m, pr, pg, pb);
  2007.  
  2008. #ifdef MDEBUG
  2009.  
  2010.       M_debug("PreserveWMcol", "Need r=%d g=%d b=%d at %d",
  2011.           pr, pg, pb, wmcolor[k].ci);
  2012.  
  2013.       M_debug("PreserveWMcol", "Found r=%d g=%d b=%d at %d with total %d",
  2014.           m->ct[0][tran], m->ct[1][tran], m->ct[2][tran], tran,
  2015.           m->colors);
  2016. #endif
  2017.  
  2018. #ifndef DOGROUP
  2019.       if (tran != wmcolor[k].ci)
  2020.         {
  2021.         modify_ci_pixel(im->raster, im->w * im->h,
  2022.                 wmcolor[k].ci, tran, 1);
  2023.         SwapMapEntry(m, wmcolor[k].ci, tran);
  2024.         }
  2025. #else
  2026.       if (tran != wmcolor[k].ci)
  2027.         {
  2028.         allt[allt[wmcolor[k].ci]] = tran;
  2029.         allt[tran] = wmcolor[k].ci;
  2030.         SwapMapEntry(m, wmcolor[k].ci, tran);
  2031.         }
  2032. #endif
  2033.       }
  2034.  
  2035.     /* reset pack flag */
  2036.     im->cmap->packed = 0;
  2037. #ifdef DOGROUP
  2038.     modify_all_ci(im->raster, im->w * im->h, allt);
  2039. #endif
  2040. }
  2041.  
  2042. #if 0                /* UNTESTED {** */
  2043. /*
  2044.  * Instead of preserve a few selected color, we try to preserval
  2045.  * all colors, upto 256
  2046.  */
  2047. void
  2048. preserve_all_colors(IPTR im)
  2049. {
  2050.     ci_t tran[MAXCML];
  2051.     int used[MAXCML];
  2052.     CMPTR m = im->cmap;
  2053.     int i, j, k;
  2054.  
  2055.     progress_report("", 100);
  2056.     for (i = 0; i < m->colors; i++)
  2057.       {
  2058.       tran[i] = i;
  2059.       used[i] = 0;
  2060.       }
  2061.  
  2062.     for (i = 0; i < m->colors; i++)
  2063.       {
  2064.       j = cmap_closematch(m, sysmap[0][i],
  2065.                   sysmap[1][i], sysmap[2][i]);
  2066.       if (!used[j] && !used[i] && i != j)
  2067.         {
  2068.         tran[tran[i]] = j;
  2069.         tran[j] = i;
  2070.         SwapMapEntry(m, i, j);
  2071.         }
  2072.       used[j] = 1;
  2073.       }
  2074.     m->packed = 0;
  2075.     modify_all_ci(im->raster, im->w * im->h, tran);
  2076.     remove_progress_report();
  2077. }
  2078. #endif /** } **/
  2079.  
  2080.  
  2081. /********************************************************************
  2082.  * simulate double buffering
  2083.  *
  2084.  * Normal Frame buffer and over/pup buffer
  2085.  *
  2086.  *******************************************************************/
  2087.  
  2088. #ifndef NO_NP_DBL
  2089.  
  2090. /***********************************************************
  2091.  * Move an object given by obj having (w,h) as its dimension
  2092.  * from (ox, oy) to (x,y).
  2093.  ***********************************************************/
  2094.  
  2095. void
  2096. sim_dbl_swap(IPTR im, int w, int h, void *obj,
  2097.          int x, int y, int ox, int oy, int mop)
  2098. {
  2099.  
  2100.     int x1, x2, y1, y2;
  2101.     int sw, sh;
  2102.     static void **scrn;
  2103.  
  2104.     set_mat_op(mop);
  2105.  
  2106.     /* if almost disjoint, not point simulating double buffering */
  2107.     if (Abs(ox - x) > (0.8 * w) && Abs(oy - y) > (0.8 * h))
  2108.       {
  2109.       void **pp;
  2110.  
  2111.       /* erase the old one */
  2112.       img_rect_redraw(im, ox, oy, w, h);
  2113.       /* draw the new one */
  2114.       pp = no_fail_get_subimage(im, x, y, w, h);
  2115.       put_submat(pp, h, w, obj, 0, 0, h, w, im->esize);
  2116.       PI_rectwrite(x, y, x + w - 1, y + h - 1, pp[0]);
  2117.       free_mat(pp);
  2118.       }
  2119.     else
  2120.       {
  2121.       x1 = Min(ox, x) - 1;
  2122.       x2 = Max(ox, x) + w + 1;
  2123.  
  2124.       y1 = Min(oy, y) - 1;
  2125.       y2 = Max(oy, y) + h + 1;
  2126.       sw = x2 - x1 + 1;
  2127.       sh = y2 - y1 + 1;
  2128.  
  2129.       free_mat(scrn);
  2130.       scrn = no_fail_get_subimage(im, x1, y1, sw, sh);
  2131.       put_submat(scrn, sh, sw, obj, y - y1, x - x1, h, w, im->esize);
  2132.       PI_rectwrite(x1, y1, x1 + sw - 1, y1 + sh - 1, scrn[0]);
  2133.       }
  2134.     set_mat_op(O_NONE);
  2135. }
  2136.  
  2137. void
  2138. mv_ras_obj(void **obj, int w, int h, int ox, int oy, int x, int y)
  2139. {
  2140.     /* sanity checks */
  2141.  
  2142.     if (!obj || !obj[0] || w <= 0 || h <= 0)
  2143.       {
  2144.       Bark("MovRasObj", "Bad input");
  2145.       return;
  2146.       }
  2147.  
  2148.     if (double_buf)
  2149.       {
  2150.       PI_rectwrite(x, y, x + w - 1, y + h - 1, obj[0]);
  2151.       swapbuffers();
  2152.       img_rect_redraw(imgptr, ox, oy, w, h);
  2153.       }
  2154.     else
  2155.       {
  2156.       sim_dbl_swap(imgptr, w, h, obj, x, y, ox, oy, O_NONE);
  2157.       }
  2158. }
  2159.  
  2160. #endif /* !NO_NP_DBL */
  2161.  
  2162. /********************************************************************
  2163.  * Get same color but with different intensity.
  2164.  * Also subject (cmin, cmax) check
  2165.  ********************************************************************/
  2166. void
  2167. scale_color(int col[], float factor, int scaled[], int cmin, int cmax)
  2168. {
  2169.  
  2170.     if (IS_CPACK(imgptr))
  2171.       {
  2172.       scaled[0] = col[0] * factor;
  2173.       scaled[1] = col[1] * factor;
  2174.       scaled[2] = col[2] * factor;
  2175.       }
  2176.     else if (IS_CI(imgptr))
  2177.       {
  2178.       CMPTR m = imgptr->cmap;
  2179.       int ci = col[4];
  2180.  
  2181.       Range(ci, 0, m->colors - 1);
  2182.       scaled[0] = factor * m->ct[0][ci];
  2183.       scaled[1] = factor * m->ct[1][ci];
  2184.       scaled[2] = factor * m->ct[2][ci];
  2185.       }
  2186.  
  2187.     Range(scaled[0], cmin, cmax);
  2188.     Range(scaled[1], cmin, cmax);
  2189.     Range(scaled[2], cmin, cmax);
  2190.  
  2191.     /* make sure we return valid PC */
  2192.     Range(scaled[0], 0, PCMAXV);
  2193.     Range(scaled[1], 0, PCMAXV);
  2194.     Range(scaled[2], 0, PCMAXV);
  2195.  
  2196.     if (IS_CI(imgptr))
  2197.       {
  2198.       scaled[3] = cmap_closematch(imgptr->cmap,
  2199.                       scaled[0],
  2200.                       scaled[1],
  2201.                       scaled[2]);
  2202.       }
  2203. }
  2204.  
  2205. /*******************************************************************
  2206.  * Return a one-liner info about image im
  2207.  ******************************************************************/
  2208. const char *
  2209. image_vital_info(IPTR im)
  2210. {
  2211.     static char buf[1024];
  2212.     sprintf(buf, "(%dX%d %s)", im->w, im->h, im->key);
  2213.     return buf;
  2214. }
  2215.  
  2216. #if 0                /** } **/
  2217. /*********************************************************************
  2218.  * Pack a char stream (with padding) to pixel in cpack format
  2219.  *********************************************************************/
  2220. void
  2221. char_stream4_cpack(register rgba_t *rgba,
  2222.            register unsigned char *pc, long total, int rgb)
  2223. {
  2224.     register rgba_t *rs = rgba + total;
  2225.  
  2226.     if (rgb)
  2227.       {
  2228.       for (; rgba < rs;)
  2229.         {
  2230.         pc++;        /* skip alpha */
  2231.         *rgba++ = Pack(*pc, *(pc + 1), *(pc + 2));
  2232.         pc += 3;
  2233.         }
  2234.       }
  2235.     else
  2236.       {
  2237.       /* in RGB order */
  2238.       for (; rgba < rs;)
  2239.         {
  2240.         pc++;        /* skip alpha */
  2241.         *rgba++ = Pack(*(pc + 2), *(pc + 1), *pc);
  2242.         pc += 3;
  2243.         }
  2244.       }
  2245. }
  2246.  
  2247. /********************************************************************
  2248.  * Pack a char stream (no padding)  bytes into a pixel
  2249.  ********************************************************************/
  2250. void
  2251. char_stream3_cpack(rgba_t *rgba, unsigned char *pc, long total, int rgb)
  2252. {
  2253.     register rgba_t *rs = rgba + total;
  2254.  
  2255.     if (rgb)
  2256.       {
  2257.       for (; rgba < rs;)
  2258.         {
  2259.         *rgba++ = Pack(*pc, *(pc + 1), *(pc + 2));
  2260.         pc += 3;
  2261.         }
  2262.       }
  2263.     else
  2264.       {
  2265.       /* in GBR order */
  2266.       for (; rgba < rs;)
  2267.         {
  2268.         *rgba++ = Pack(*(pc + 2), *(pc + 1), *pc);
  2269.         pc += 3;
  2270.         }
  2271.       }
  2272. }
  2273.  
  2274. #endif /** } **/
  2275.  
  2276. /**********************************************************************
  2277.  * Anti-aliasing
  2278.  *   It doesn't look right if linewidth != 1 or the linestyle is
  2279.  *   not solid
  2280.  *********************************************************************/
  2281. void
  2282. smooth_line_on(IPTR im, int *col, int lw)
  2283. {
  2284.     Color4(col);
  2285.  
  2286.     if (smooth_lines && getlstyle() == 0 &&
  2287.     sml_capable() && lw == 1 && IS_CPACK(im))
  2288.       {
  2289.       pntsmooth(SMP_ON | SMP_SMOOTHER);
  2290.       linesmooth(SML_ON | SML_SMOOTHER | SML_END_CORRECT);
  2291.       blendfunction(BF_SA, BF_MSA);
  2292.       subpixel(1);
  2293.       cpack(Pack(col[0], col[1], col[2]) | 0xff000000);
  2294.       }
  2295. }
  2296.  
  2297. /*********** Turn anti-aliasing off ******************/
  2298. void
  2299. smooth_line_off(IPTR im, int *col)
  2300. {
  2301.     pntsmooth(SMP_OFF);
  2302.     linesmooth(SML_OFF);
  2303.     blendfunction(BF_ONE, BF_ZERO);
  2304.     subpixel(0);
  2305.     if (IS_CPACK(im))
  2306.     cpack(Pack(col[0], col[1], col[2]));
  2307. }
  2308.  
  2309. /************************************************************
  2310.  * Convert X11 bitmap to GL 32x32 patterns
  2311.  ************************************************************/
  2312. #define getbits(a, k, i)      ((a[(k)] >> (i))&1)
  2313. #define GL_pat unsigned short
  2314.  
  2315. GL_pat *
  2316. XBM_to_GL_pat(int w, int h, char *bits)
  2317. {
  2318.     GL_pat *pat, *cpat;
  2319.     int i, j, k, on, total;
  2320.  
  2321.     if (w != 32 || h != 32 || !bits)
  2322.       {
  2323.       M_err("XBM2GLPAT", "Bad input w=%d h=%d", w, h);
  2324.       return 0;
  2325.       }
  2326.  
  2327.     total = (w / 16) * h;
  2328.  
  2329.     /* do the conversion */
  2330.     pat = calloc((total + 1), sizeof(*pat));
  2331.     cpat = pat + total - 1;
  2332.  
  2333.     for (k = j = 0; j < h; j++)
  2334.       {
  2335.       for (i = 0; i < w; i++)
  2336.         {
  2337.         on = (bits[k + i / 8] & (1 << (i % 8))) != 0;
  2338.         *(cpat - (i / 16)) |= on << (15 - (i % 16));
  2339.         }
  2340.       k += (w + 7) / 8;
  2341.       cpat -= (w + 15) / 16;
  2342.       }
  2343.     return pat;
  2344. }
  2345.  
  2346. const Rect_t *
  2347. img_rect(IPTR im)
  2348. {
  2349.     static Rect_t dummy[5];
  2350.     static int np;
  2351.     Rect_t *r;
  2352.  
  2353.     r = dummy + np++;
  2354.  
  2355.     r->x = im->xi;
  2356.     r->y = im->yi;
  2357.     r->w = im->w;
  2358.     r->h = im->h;
  2359.  
  2360.     np %= 5;
  2361.     return r;
  2362. }
  2363.